package com.fingard.dsp.bank.directbank.nnbill01;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bill99.sdk.crypto.process.CryptoProcessorFactory;
import com.bill99.sdk.crypto.schema.CmsSignedAndEnveloped;
import com.fingard.constant.Format;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.FailCode;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.bankInterface.IBatPayRec;
import com.fingard.dsp.bank.directbank.nnbill01.util.Cons;
import com.fingard.dsp.bank.directbank.nnbill01.util.GZIPUtil;
import com.fingard.dsp.bank.directbank.nnbill01.util.MerchantPKIUtils;
import com.fingard.dsp.bank.directbank.nnbill01.wsdl.batch.DealInfoEntity;
import com.fingard.dsp.bank.directbank.nnbill01.wsdl.batch.GzipUtil;
import com.fingard.dsp.bank.directbank.nnbill01.wsdl.batch.OrderInfoEntity;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.detail.RetAtsBatPayRecDetail;
import com.fingard.io.FileHelper;
import com.fingard.text.AESHelper;
import com.fingard.text.StringHelper;
import com.fingard.xml.XmlTextReader;
import org.apache.commons.codec.binary.Base64;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 快钱商业委托及协议代扣
 */
public class NNBill01BatPayRec extends NNBill01Base implements IBatPayRec {
    @Override
    public RetAtsBatPayRec d_1988_BatPay(ReqBatPayRec p_req1988) throws Exception {
        return d_BatPayRec(p_req1988);
    }

    @Override
    public RetAtsQryBatPayRec d_1998_QryBatPay(ReqQryBatPayRec p_req1998) throws Exception {
        return d_QryBatPayRec(p_req1998);
    }

    @Override
    public RetAtsBatPayRec d_9188_BatPay(ReqBatPayRec p_req9188) throws Exception {
        return d_BatPayRec(p_req9188);
    }

    @Override
    public RetAtsQryBatPayRec d_9198_QryBatPay(ReqQryBatPayRec p_req9198) throws Exception {
        return d_QryBatPayRec(p_req9198);
    }

    public RetAtsBatPayRec d_BatPayRec(ReqBatPayRec p_reqBat) throws Exception {
        if ("9188Agrm".equals(p_reqBat.reqHeader.commandCode)) {
            return submit9188Agrm(p_reqBat);
        } else if ("9188Auth".equals(p_reqBat.reqHeader.commandCode)) {
            return submit9188Auth(p_reqBat);
        } else if ("1988Batch".equals(p_reqBat.reqHeader.commandCode)) {
            return submit1988Batch(p_reqBat);
        } else {
            RetAtsBatPayRec retAts = new RetAtsBatPayRec(p_reqBat.reqHeader);
            retAts.respCode = "0";
            retAts.respInfo = "不支持的代扣指令:[" + p_reqBat.reqHeader.commandCode + "],请检查ATS请求报文的'CommandCode'标签值!";
            retAts.transState = PaymentState.FAIL_Batch;
            retAts.payInfoCode = FailCode.E9981;
            retAts.writeRetToATS();
            return retAts;
        }
    }

    private RetAtsBatPayRec submit1988Batch(ReqBatPayRec p_reqBat) {
        RetAtsBatPayRec retAts = new RetAtsBatPayRec(p_reqBat.reqHeader);
        retAts.reqSeqID = p_reqBat.reqBatchNO;
        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_reqBat.ownAct, "batPay");
            if (actItem == null) {
                retAts.respCode = "0";
                retAts.respInfo = "未找到账号[" + p_reqBat.ownAct + "]商户配置信息,请检查config.xml中'actSet'相关配置!";
                retAts.transState = PaymentState.FAIL_Batch;
                retAts.payInfoCode = FailCode.E9981;
                retAts.writeRetToATS();
                return retAts;
            }

            List<OrderInfoEntity> ordersInfo = new ArrayList<OrderInfoEntity>();
            while (p_reqBat.readRecord()) {
                OrderInfoEntity orderInfo = new OrderInfoEntity();
                orderInfo.setMerchantId(p_reqBat.readedDetail.askNumber);/** 商家订单号 */
                orderInfo.setAmt(StringHelper.amountMultiply100(p_reqBat.readedDetail.payAmount));/** 金额 */
                orderInfo.setBank(p_reqBat.readedDetail.payBankName);/** 银行名称 */
                orderInfo.setName(p_reqBat.readedDetail.payName);/** 户名 */
                orderInfo.setBankCardNo(p_reqBat.readedDetail.payAct);/** 卡号 */
                orderInfo.setBranchBank(p_reqBat.readedDetail.payBankLocation);/** 开户行 */
                if ("1".equals(p_reqBat.readedDetail.isPrivate)) {
                    orderInfo.setPayeeType("1");/** 对公对私 */
                } else {
                    orderInfo.setPayeeType("0");
                }
                orderInfo.setProvince(p_reqBat.readedDetail.getOppProvinceAndCity()[0]);/** 省份 */
                orderInfo.setCity(p_reqBat.readedDetail.getOppProvinceAndCity()[1]);/** 城市 */
                orderInfo.setMemo(p_reqBat.readedDetail.memo);/** 快钱交易备注 */
                orderInfo.setBankPurpose(p_reqBat.readedDetail.memo);/** 银行交易用备注 */
                orderInfo.setBankMemo(p_reqBat.readedDetail.transInfo);/** 银行交易备注 */
                orderInfo.setPayeeNote(p_reqBat.readedDetail.memo);/** 收款方通知知内容 */
                orderInfo.setPayeeMobile(p_reqBat.readedDetail.cellPhone);/** 收款方手机号 */
                orderInfo.setPayeeEmail("");/** 收款方邮件 */
                orderInfo.setPeriod("");/** 到账时效 */
                orderInfo.setMerchantMemo1("");/** 商户预留字段1 */
                orderInfo.setMerchantMemo2("");/** 商户预留字段2 */
                orderInfo.setMerchantMemo3("");/** 商户预留字段3 */
                ordersInfo.add(orderInfo);
            }
            DealInfoEntity dealInfo = new DealInfoEntity();
            dealInfo.setPayerAcctCode(actItem.inMerchantId);/** 付款方帐号 */
            dealInfo.setBatchNo(p_reqBat.reqBatchNO);/** 批次号 */
            dealInfo.setApplyDate(Format.DateTime14Format.format(new Date()));/** 发起日期 */
            dealInfo.setName(p_reqBat.ownActName);/** 付款商户名称 */
            dealInfo.setTotalAmt(StringHelper.amountMultiply100(p_reqBat.totalAmt));/** 总金额 */
            dealInfo.setTotalCnt(p_reqBat.totalNum);/** 总笔额 */
            dealInfo.setFeeType("1");/** 打款手续费付费方式 1.付款方付费 0.收款方付费*/
            dealInfo.setCur("RMB");/** 币种 */
            dealInfo.setCheckAmtCnt("0");/** 是否验证金额 */
            dealInfo.setBatchFail("1");/** 是否整批失败 */
            dealInfo.setRechargeType("1");/** 充值方式 */
            dealInfo.setAutoRefund("0");/** 是否自动退款 */
            dealInfo.setPhoneNoteFlag("1");/** 是否短信通知 */
            dealInfo.setMerchantMemo1("");/** 预留字段1 */
            dealInfo.setMerchantMemo2("");/** 预留字段2 */
            dealInfo.setMerchantMemo3("");/** 预留字段3 */
            dealInfo.setOrdersInfo(ordersInfo);

            dealInfo.setServiceType("fo.batch.settlement.pay");/** 提交类型 */
            dealInfo.setVersion("1.0.1");/** 版本号 */
            String featureCodebatch = getBankConfig().getValueAsString("featureCodebatch");
            if (StringHelper.hasAnyChar(featureCodebatch)) {
                dealInfo.setFeatureCode(featureCodebatch);
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = "请求报文中featureCodebatch节点为空，请检查NNBill01/config.xml中'featureCodebatch'节点配置";
                return retAts;
            }
            dealInfo.setMemberCode(actItem.merchantId);

            String url = bankFront.getUrl("batPay");
            if ("F889".equalsIgnoreCase(dealInfo.getFeatureCode())) {
                String response = apply_ws(dealInfo, actItem, url);
                WriteBankLogStep3(response);
                StringBuilder tmpSbMsg1 = new StringBuilder();
                XmlTextReader tmpBkReader1 = loadBankRespXmlReader(response, tmpSbMsg1);
                // 交易状态码
                String errorCode = tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:error-code");
                // 交易返回信息
                String backErrorMsg = tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:error-msg");
                if ("0000".equals(errorCode)) {
                    byte[] backSignBytes = Base64.decodeBase64(tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:data/ns1:signed-data").getBytes(getCharset()));
                    byte[] backencryptBytes = Base64.decodeBase64(tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:data/ns1:encrypted-data").getBytes(getCharset()));
                    byte[] backDigitalBytes = Base64.decodeBase64(tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:data/ns1:digital-envelope").getBytes(getCharset()));
                    // 解密数字信封
                    byte[] backKey = decryptByPKRSA(backDigitalBytes, actItem);
                    // 返回原文
                    byte[] backOriginalBytes = AESHelper.decodeAES(backKey, backencryptBytes);
                    byte[] originalBytes =GzipUtil.unBGzip(backOriginalBytes);

                    String respObject = new String(originalBytes, getCharset());
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(respObject, tmpSbMsg);
                    WriteBankLogLn("解密后的银行返回文件为:" + respObject);
                    if (!"".equals(tmpBkReader)) {
                        if (tmpBkReader.read("/tns:batch-settlement-apply-response/tns:response-body/tns:pay2bank-list/tns:pay2bank-result")) {
                            retAts.respCode = "0";
                            retAts.respInfo = "提交成功";
                            retAts.transState = tmpBkReader.readedXElement.getSingleTextNotNull("tns:status");
                            retAts.payInfoCode = errorCode;
                        }
                    } else {
                        retAts.respCode = "-1";
                        retAts.respInfo = "银行返回内容为空!";
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = backErrorMsg;
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            WriteBankLogLn(ex);
        }
        retAts.writeRetToATS();
        return retAts;
    }

    /**
     * 批量协议代扣
     *
     * @param p_reqBat
     * @return
     * @throws Exception
     */
    public RetAtsBatPayRec submit9188Agrm(ReqBatPayRec p_reqBat) throws Exception {
        RetAtsBatPayRec retAts = new RetAtsBatPayRec(p_reqBat.reqHeader);
        retAts.reqSeqID = p_reqBat.reqBatchNO;

        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_reqBat.ownAct, "");
            if (actItem == null ) {
                retAts.respCode = "0";
                retAts.respInfo = "未找到账号[" + p_reqBat.ownAct + "]商户配置信息,请检查config.xml中'actSet'相关配置!";
                retAts.transState = PaymentState.FAIL_Batch;
                retAts.payInfoCode = FailCode.E9981;
                retAts.writeRetToATS();
                return retAts;
            }

            JSONObject reqJson = new JSONObject();
            JSONObject reqHeaderJson = new JSONObject();
            reqHeaderJson.put("version","1.0.0");
            reqHeaderJson.put("messageType",NNBill01TransCode.batrec_9188Agrm_submit);
            reqHeaderJson.put("memberCode",actItem.inMerchantId);
            reqHeaderJson.put("requestId",p_reqBat.reqBatchNO);
            reqJson.put("head",reqHeaderJson);

            JSONObject reqBodyJson = new JSONObject();
            reqBodyJson.put("merchantId", actItem.merchantId);
            reqBodyJson.put("terminalId", actItem.termId);
            reqBodyJson.put("requestTime", Format.DateTime14Format.format(new Date()));
            reqBodyJson.put("numTotal", p_reqBat.totalNum);
            reqBodyJson.put("amountTotal", StringHelper.amountMultiply100(p_reqBat.totalAmt));

            JSONArray txnListArray = new JSONArray();
            while(p_reqBat.readRecord()) {
                JSONObject eachJson = new JSONObject();

                eachJson.put("externalRefNumber",p_reqBat.readedDetail.askNumber);
                eachJson.put("customerId",p_reqBat.readedDetail.customNo);
                eachJson.put("payToken",p_reqBat.readedDetail.sourceNoteCode);
                eachJson.put("amount",StringHelper.amountMultiply100(p_reqBat.readedDetail.payAmount));
                eachJson.put("zbxAuthOrderId","");
                eachJson.put("ext",p_reqBat.readedDetail.askNumber);
                eachJson.put("ext1","");
                eachJson.put("bindType","0");
                eachJson.put("deviceType","");
                eachJson.put("deviceNo","");
                eachJson.put("sourceIp","");
                eachJson.put("sourceMacAddr","");
                eachJson.put("sourceImei","");
                eachJson.put("sourceIccid","");
                eachJson.put("sourceWifiMacAddr","");
                eachJson.put("lbs","");
                eachJson.put("sourceImsi","");
                eachJson.put("storablePan","");
                eachJson.put("settleMerchantId","");
                eachJson.put("minamount","");
                eachJson.put("UnderamountId","");
                txnListArray.add(eachJson);
            }
            String txnList = txnListArray.toJSONString();
            WriteBankLogLn2("txnList:" + txnList);
            String gzipList = GZIPUtil.gzip2(txnList, "UTF-8");
            reqBodyJson.put("txnList", gzipList);
            reqJson.put("body",reqBodyJson);
            reqJson.put("memberCode",actItem.inMerchantId);

            String[] tmpStrRet = sendDataToBank(actItem,reqJson, bankFront.getUrl("batUnified"));

            if (tmpStrRet[0].length() == 0) {
                JSONObject respJsonObject = JSONObject.parseObject(tmpStrRet[1]);
                String respHead = respJsonObject.getString(Cons.HEAD);
                String respBody = respJsonObject.getString(Cons.RESPONSE_BODY);
                if(respHead == null || respBody == null) {
                    retAts.respCode = "0";
                    retAts.respInfo = "app-umgw返回报文head或responseBody节点缺失";
                    retAts.transState = PaymentState.FAIL_Batch;
                    retAts.payInfoCode = FailCode.E9981;
                    retAts.writeRetToATS();
                    return retAts;
                }
                JSONObject respHeadJsonObject = JSONObject.parseObject(respHead);
                JSONObject respBodyJsonObject = JSONObject.parseObject(respBody);
                if(respHeadJsonObject.isEmpty()) {
                    retAts.respCode = "0";
                    retAts.respInfo = "app-umgw返回报文head节点内容为空";
                    retAts.transState = PaymentState.FAIL_Batch;
                    retAts.payInfoCode = FailCode.E9981;
                    retAts.writeRetToATS();
                    return retAts;
                }
                JSONObject decryptJO = new JSONObject();
                if(!respBodyJsonObject.isEmpty()) {
                    CmsSignedAndEnveloped respEncryptObj = JSONObject.toJavaObject(respBodyJsonObject,CmsSignedAndEnveloped.class);
                    CryptoProcessorFactory.initCertDir(actItem.oppCertFilePath);
                    CryptoProcessorFactory.initCertDir(actItem.ownKeyStorePath);
                    decryptJO = MerchantPKIUtils.decrypt(actItem.oppCertFilePath, actItem.ownKeyStorePath, respEncryptObj);
                    WriteBankLogLn2("快钱响应明文body的json:\r\n" + JSON.toJSONString(decryptJO));
                }
                JSONObject respView = new JSONObject();
                respView.put(Cons.HEAD, respHeadJsonObject);
                respView.put(Cons.RESPONSE_BODY, decryptJO);
                WriteBankLogLn2("解密后报文明文数据:\r\n" + JSON.toJSONString(respView));

                retAts.respCode = "0";
                retAts.respInfo = respHeadJsonObject.getString("responseTextMessage");
                String tmpRespCode = respHeadJsonObject.getString("responseCode");
                if ("0000".equals(tmpRespCode)) {
                    retAts.transState = decryptJO.getString("batchResult");
                    retAts.payInfoCode = decryptJO.getString("batchResult");
                    String bankBatchId = decryptJO.getString("batchId");
                    FileHelper.writeFile(getTempFileDirectory(p_reqBat.getPayDateTime()) + File.separator + p_reqBat.reqBatchNO + ".txt", bankBatchId, getCharset());
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = respHeadJsonObject.getString("responseTextMessage");
                }
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = "银行返回内容为空!";
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            WriteBankLogLn(ex);
        }

        retAts.writeRetToATS();
        return retAts;
    }

    /**
     * 批量委托代扣
     *
     * @param p_reqBat
     * @return
     * @throws Exception
     */
    public RetAtsBatPayRec submit9188Auth(ReqBatPayRec p_reqBat) throws Exception {
        RetAtsBatPayRec retAts = new RetAtsBatPayRec(p_reqBat.reqHeader);
        retAts.reqSeqID = p_reqBat.reqBatchNO;

        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_reqBat.ownAct, "");
            if (actItem == null ) {
                retAts.respCode = "0";
                retAts.respInfo = "未找到账号[" + p_reqBat.ownAct + "]商户配置信息,请检查config.xml中'actSet'相关配置!";
                retAts.transState = PaymentState.FAIL_Batch;
                retAts.payInfoCode = FailCode.E9981;
                retAts.writeRetToATS();
                return retAts;
            }

            JSONObject reqJson = new JSONObject();
            JSONObject reqHeaderJson = new JSONObject();
            reqHeaderJson.put("version","1.0.0");
            reqHeaderJson.put("messageType",NNBill01TransCode.batrec_9188Auth_submit);
            reqHeaderJson.put("memberCode",actItem.inMerchantId);
            reqHeaderJson.put("requestId",p_reqBat.reqBatchNO);
            reqJson.put("head",reqHeaderJson);

            JSONObject reqBodyJson = new JSONObject();
            reqBodyJson.put("merchantId", actItem.merchantId);
            reqBodyJson.put("terminalId", actItem.termId);
            reqBodyJson.put("requestTime", Format.DateTime14Format.format(new Date()));
            reqBodyJson.put("numTotal", p_reqBat.totalNum);
            reqBodyJson.put("amountTotal", StringHelper.amountMultiply100(p_reqBat.totalAmt));

            JSONArray txnListArray = new JSONArray();
            while(p_reqBat.readRecord()) {
                JSONObject eachJson = new JSONObject();

                eachJson.put("externalRefNumber",p_reqBat.readedDetail.askNumber);
                eachJson.put("customerId",p_reqBat.readedDetail.customNo);
                eachJson.put("payToken",p_reqBat.readedDetail.sourceNoteCode);
                eachJson.put("amount",StringHelper.amountMultiply100(p_reqBat.readedDetail.payAmount));
                eachJson.put("zbxAuthOrderId","");
                eachJson.put("ext",p_reqBat.readedDetail.askNumber);
                eachJson.put("ext1","");
                eachJson.put("bindType","0");
                eachJson.put("deviceType","");
                eachJson.put("deviceNo","");
                eachJson.put("sourceIp","");
                eachJson.put("sourceMacAddr","");
                eachJson.put("sourceImei","");
                eachJson.put("sourceIccid","");
                eachJson.put("sourceWifiMacAddr","");
                eachJson.put("lbs","");
                eachJson.put("sourceImsi","");
                eachJson.put("pan","");
                eachJson.put("expiredDate",p_reqBat.readedDetail.expiredDate);
                eachJson.put("cvv2",p_reqBat.readedDetail.cvv2);
                eachJson.put("cardHolderName","");
                eachJson.put("cardHolderId","");
                eachJson.put("idType","");
                eachJson.put("phoneNo","");
                eachJson.put("note","");
                txnListArray.add(eachJson);
            }
            String txnList = txnListArray.toJSONString();
            WriteBankLogLn2("txnList:" + txnList);
            String gzipList = GZIPUtil.gzip2(txnList, "UTF-8");
            reqBodyJson.put("txnList", gzipList);
            reqJson.put("body",reqBodyJson);
            reqJson.put("memberCode",actItem.inMerchantId);

            String[] tmpStrRet = sendDataToBank(actItem,reqJson, bankFront.getUrl("batUnified"));

            if (tmpStrRet[0].length() == 0) {
                JSONObject respJsonObject = JSONObject.parseObject(tmpStrRet[1]);
                String respHead = respJsonObject.getString(Cons.HEAD);
                String respBody = respJsonObject.getString(Cons.RESPONSE_BODY);
                if(respHead == null || respBody == null) {
                    retAts.respCode = "0";
                    retAts.respInfo = "app-umgw返回报文head或responseBody节点缺失";
                    retAts.transState = PaymentState.FAIL_Batch;
                    retAts.payInfoCode = FailCode.E9981;
                    retAts.writeRetToATS();
                    return retAts;
                }
                JSONObject respHeadJsonObject = JSONObject.parseObject(respHead);
                JSONObject respBodyJsonObject = JSONObject.parseObject(respBody);
                if(respHeadJsonObject.isEmpty()) {
                    retAts.respCode = "0";
                    retAts.respInfo = "app-umgw返回报文head节点内容为空";
                    retAts.transState = PaymentState.FAIL_Batch;
                    retAts.payInfoCode = FailCode.E9981;
                    retAts.writeRetToATS();
                    return retAts;
                }
                JSONObject decryptJO = new JSONObject();
                if(!respBodyJsonObject.isEmpty()) {
                    CmsSignedAndEnveloped respEncryptObj = JSONObject.toJavaObject(respBodyJsonObject,CmsSignedAndEnveloped.class);
                    CryptoProcessorFactory.initCertDir(actItem.oppCertFilePath);
                    CryptoProcessorFactory.initCertDir(actItem.ownKeyStorePath);
                    decryptJO = MerchantPKIUtils.decrypt(actItem.oppCertFilePath, actItem.ownKeyStorePath, respEncryptObj);
                    WriteBankLogLn2("快钱响应明文body的json:\r\n" + JSON.toJSONString(decryptJO));
                }
                JSONObject respView = new JSONObject();
                respView.put(Cons.HEAD, respHeadJsonObject);
                respView.put(Cons.RESPONSE_BODY, decryptJO);
                WriteBankLogLn2("解密后报文明文数据:\r\n" + JSON.toJSONString(respView));

                retAts.respCode = "0";
                retAts.respInfo = respHeadJsonObject.getString("responseTextMessage");
                String tmpRespCode = respHeadJsonObject.getString("responseCode");
                if ("0000".equals(tmpRespCode)) {
                    retAts.transState = decryptJO.getString("batchResult");
                    retAts.payInfoCode = decryptJO.getString("batchResult");
                    String bankBatchId = decryptJO.getString("batchId");
                    FileHelper.writeFile(getTempFileDirectory(p_reqBat.getPayDateTime()) + File.separator + p_reqBat.reqBatchNO + ".txt", bankBatchId, getCharset());
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = respHeadJsonObject.getString("responseTextMessage");
                }
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = "银行返回内容为空!";
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            WriteBankLogLn(ex);
        }

        retAts.writeRetToATS();
        return retAts;
    }

    public RetAtsQryBatPayRec d_QryBatPayRec(ReqQryBatPayRec p_reqQryBat) throws Exception {
        if ("9188Agrm".equals(p_reqQryBat.reqHeader.commandCode)) {
            return qry9188Agrm(p_reqQryBat);
        } else if ("9188Auth".equals(p_reqQryBat.reqHeader.commandCode)) {
            return qry9188Auth(p_reqQryBat);
        } else if ("1988Batch".equals(p_reqQryBat.reqHeader.commandCode)) {
            return qry1988Batch(p_reqQryBat);
        } else {
            RetAtsQryBatPayRec retAts = new RetAtsQryBatPayRec(p_reqQryBat.reqHeader);
            retAts.reqSeqID = p_reqQryBat.reqBatchNO;
            retAts.respCode = "-1";
            retAts.respInfo = "不支持的查询指令:[" + p_reqQryBat.reqHeader.commandCode + "],请检查ATS请求报文的'CommandCode'标签值!";
            retAts.writeAfterDetail();
            return retAts;
        }
    }

    private RetAtsQryBatPayRec qry1988Batch(ReqQryBatPayRec p_reqQryBat) throws Exception {
        RetAtsQryBatPayRec retAts = new RetAtsQryBatPayRec(p_reqQryBat.reqHeader);
        retAts.reqSeqID = p_reqQryBat.reqBatchNO;

        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_reqQryBat.ownAct, "batQuery");
            if (actItem == null ) {
                retAts.respCode = "0";
                retAts.respInfo = "未找到账号[" + p_reqQryBat.ownAct + "]商户配置信息,请检查config.xml中'actSet'相关配置!";
                retAts.transState = PaymentState.FAIL_Batch;
                retAts.payInfoCode = FailCode.E9981;
                retAts.writeAfterDetail();
                return retAts;
            }

            DealInfoEntity dealInfo = new DealInfoEntity();
            dealInfo.setBatchNo(p_reqQryBat.reqBatchNO);

            dealInfo.setListFlag("0");
            dealInfo.setPage("1");
            dealInfo.setPageSize("1000");
            dealInfo.setServiceType("fo.batch.settlement.batchidquery");
            dealInfo.setVersion("1.0");
            String featureCodebatch = getBankConfig().getValueAsString("featureCodebatch");
            if (StringHelper.hasAnyChar(featureCodebatch)) {
                dealInfo.setFeatureCode(featureCodebatch);
            } else {
                retAts.writeRespCode("-1");
                retAts.writeRespInfo("请求报文中featureCodebatch节点为空，请检查NNBill01/config.xml中'featureCodebatch'节点配置");
                return retAts;
            }
            dealInfo.setMemberCode(actItem.merchantId);

            String url = bankFront.getUrl("batQuery");
            if ("F889".equalsIgnoreCase(dealInfo.getFeatureCode())) {
                String response = apply_ws(dealInfo, actItem, url);
                WriteBankLogStep3(response);
                StringBuilder tmpSbMsg1 = new StringBuilder();
                XmlTextReader tmpBkReader1 = loadBankRespXmlReader(response, tmpSbMsg1);
                // 交易状态码
                String errorCode = tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:error-code");
                // 交易返回信息
                String backErrorMsg = tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:error-msg");
                if ("0000".equals(errorCode)) {
                    byte[] backSignBytes = Base64.decodeBase64(tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:data/ns1:signed-data").getBytes(getCharset()));
                    byte[] backencryptBytes = Base64.decodeBase64(tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:data/ns1:encrypted-data").getBytes(getCharset()));
                    byte[] backDigitalBytes = Base64.decodeBase64(tmpBkReader1.getFirstText("/tns:settlement-pki-api-response/tns:response-body/tns:data/ns1:digital-envelope").getBytes(getCharset()));
                    // 解密数字信封
                    byte[] backKey = decryptByPKRSA(backDigitalBytes, actItem);
                    // 返回原文
                    byte[] backOriginalBytes = AESHelper.decodeAES(backKey, backencryptBytes);
                    byte[] originalBytes =GzipUtil.unBGzip(backOriginalBytes);

                    String respObject = new String(originalBytes, getCharset());
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(respObject, tmpSbMsg);
                    WriteBankLogLn("解密后的银行返回文件为:" + respObject);
                    if (!"".equals(tmpBkReader)) {
                        String status = tmpBkReader.getFirstText("/tns:batchid-query-response/tns:response-body/tns:batchList/tns:pay2bank-list/tns:pay2bank-result/tns:status");
                        if (StringHelper.hasAnyChar(status)) {
                            retAts.respCode = "0";
                            retAts.respInfo = "查询成功";
                            while (tmpBkReader.read("/tns:batchid-query-response/tns:response-body/tns:batchList/tns:pay2bank-list/tns:pay2bank-result/tns:pay2bank")) {
                                RetAtsBatPayRecDetail tmpRetDetail = new RetAtsBatPayRecDetail();
                                tmpRetDetail.payName = tmpBkReader.readedXElement.getSingleTextNotNull("ns1:name");
                                tmpRetDetail.payAmount = tmpBkReader.readedXElement.getSingleTextNotNull("ns1:amt");
                                tmpRetDetail.payAct = tmpBkReader.readedXElement.getSingleTextNotNull("ns1:bank-card-no");
                                tmpRetDetail.postScript = tmpBkReader.readedXElement.getSingleTextNotNull("ns1:merchant-id");
                                tmpRetDetail.usage = tmpBkReader.readedXElement.getSingleTextNotNull("memo");
                                tmpRetDetail.payInfoCode = status;
                                retAts.writeRetDetail(tmpRetDetail);
                            }
                        } else {
                            retAts.respCode = "0";
                            retAts.respInfo = status;
                        }
                    } else {
                        retAts.respCode = "-1";
                        retAts.respInfo = "银行返回内容为空!";
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = backErrorMsg;
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            WriteBankLogLn(ex);
        }

        retAts.writeAfterDetail();
        return retAts;
    }

    /**
     * 批量协议支付查询
     *
     * @param p_reqQryBat
     * @return
     * @throws Exception
     */
    public RetAtsQryBatPayRec qry9188Agrm(ReqQryBatPayRec p_reqQryBat) throws Exception {
        RetAtsQryBatPayRec retAts = new RetAtsQryBatPayRec(p_reqQryBat.reqHeader);
        retAts.reqSeqID = p_reqQryBat.reqBatchNO;

        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_reqQryBat.ownAct,"");
            if (actItem != null) {
                String tmpBankBatchIdPath = getTempFileDirectory(p_reqQryBat.getBgnDateTime()) + File.separator + p_reqQryBat.reqBatchNO + ".txt";
                WriteBankLogLn2("快钱批次号映射文件路径:" + tmpBankBatchIdPath);
                if (!new File(tmpBankBatchIdPath).exists()) {
                    retAts.respCode = "-1";
                    retAts.respInfo = "本地未找到快钱批次号映射文件:" + tmpBankBatchIdPath;
                    retAts.writeAfterDetail();
                    return retAts;
                }
                String bankBatchId = FileHelper.readFileText(tmpBankBatchIdPath, getCharset());
                WriteBankLogLn2("快钱批次号映射文件内容:" + bankBatchId);

                JSONObject reqJson = new JSONObject();
                JSONObject reqHeaderJson = new JSONObject();
                reqHeaderJson.put("version","1.0.0");
                reqHeaderJson.put("messageType",NNBill01TransCode.batrec_9188Agrm_query);
                reqHeaderJson.put("memberCode",actItem.inMerchantId);
                reqHeaderJson.put("batchId",bankBatchId);
                reqJson.put("head",reqHeaderJson);

                JSONObject reqBodyJson = new JSONObject();
                reqBodyJson.put("requestTime", Format.DateTime14Format.format(new Date()));
                reqBodyJson.put("startTime", "");
                reqBodyJson.put("endTime", "");
                reqBodyJson.put("externalRefNumber", "");
                reqBodyJson.put("txnStatus", "");
                reqBodyJson.put("pageNo", "1");
                reqBodyJson.put("pageSize", "1000");
                reqJson.put("body",reqBodyJson);
                reqJson.put("memberCode",actItem.inMerchantId);

                String[] tmpStrRet = sendDataToBank(actItem,reqJson, bankFront.getUrl("batUnified"));

                if (tmpStrRet[0].length() == 0) {
                    JSONObject respJsonObject = JSONObject.parseObject(tmpStrRet[1]);
                    String respHead = respJsonObject.getString(Cons.HEAD);
                    String respBody = respJsonObject.getString(Cons.RESPONSE_BODY);
                    if(respHead == null || respBody == null) {
                        retAts.respCode = "-1";
                        retAts.respInfo = "app-umgw返回报文head或responseBody节点缺失";
                        retAts.writeAfterDetail();
                        return retAts;
                    }
                    JSONObject respHeadJsonObject = JSONObject.parseObject(respHead);
                    JSONObject respBodyJsonObject = JSONObject.parseObject(respBody);
                    if(respHeadJsonObject.isEmpty()) {
                        retAts.respCode = "-1";
                        retAts.respInfo = "app-umgw返回报文head节点内容为空";
                        retAts.writeAfterDetail();
                        return retAts;
                    }
                    JSONObject decryptJO = new JSONObject();
                    if(!respBodyJsonObject.isEmpty()) {
                        CmsSignedAndEnveloped respEncryptObj = JSONObject.toJavaObject(respBodyJsonObject,CmsSignedAndEnveloped.class);
                        CryptoProcessorFactory.initCertDir(actItem.oppCertFilePath);
                        CryptoProcessorFactory.initCertDir(actItem.ownKeyStorePath);
                        decryptJO = MerchantPKIUtils.decrypt(actItem.oppCertFilePath, actItem.ownKeyStorePath, respEncryptObj);
                        WriteBankLogLn2("快钱响应明文body的json:\r\n" + JSON.toJSONString(decryptJO));
                    }
                    JSONObject respView = new JSONObject();
                    respView.put(Cons.HEAD, respHeadJsonObject);
                    respView.put(Cons.RESPONSE_BODY, decryptJO);
                    WriteBankLogLn2("解密后报文明文数据:\r\n" + JSON.toJSONString(respView));

                    String tmpRespCode = respHeadJsonObject.getString("responseCode");
                    if ("0000".equals(tmpRespCode)) {
                        retAts.respCode = "0";
                        String txnListContent = decryptJO.getString("txnList");
                        if(StringHelper.isNullOrEmpty(txnListContent)) {
                            retAts.respCode = "-1";
                            retAts.respInfo = "postRendering:respBody:txnList is null or a empty string";
                            retAts.writeAfterDetail();
                            return retAts;
                        }
                        String txnList = GZIPUtil.unGzip2(txnListContent, "UTF-8");
                        WriteBankLogLn2("postRendering:respBody:txnList=\r\n" + txnList);

                        JSONArray txnListArray = JSONArray.parseArray(txnList);
                        for(int i = 0; i < txnListArray.size(); i++){
                            JSONObject jsonDetail = txnListArray.getJSONObject(i);
                            RetAtsBatPayRecDetail tmpRetDetail = new RetAtsBatPayRecDetail();

                            tmpRetDetail.payAmount = StringHelper.amountDivide100(jsonDetail.getString("amount"));
                            tmpRetDetail.postScript = jsonDetail.getString("externalRefNumber");
                            tmpRetDetail.result = jsonDetail.getString("txnStatus");
                            tmpRetDetail.payInfoCode = jsonDetail.getString("bizResponseCode");
                            tmpRetDetail.memo = jsonDetail.getString("bizResponseMessage");
                            retAts.writeRetDetail(tmpRetDetail);
                        }
                    } else {
                        retAts.respCode = "-1";
                        retAts.respInfo = respHeadJsonObject.getString("responseTextMessage");
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = "银行返回内容为空!";
                }
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = "未找到账号[" + p_reqQryBat.ownAct + "]商户配置信息,请检查config.xml中'actSet'相关配置!";
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            WriteBankLogLn(ex);
        }

        retAts.writeAfterDetail();
        return retAts;
    }

    /**
     * 批量商业委托代扣查询
     *
     * @param p_reqQryBat
     * @return
     * @throws Exception
     */
    public RetAtsQryBatPayRec qry9188Auth(ReqQryBatPayRec p_reqQryBat) throws Exception {
        RetAtsQryBatPayRec retAts = new RetAtsQryBatPayRec(p_reqQryBat.reqHeader);
        retAts.reqSeqID = p_reqQryBat.reqBatchNO;

        try {
            ActSetItem actItem = getBankConfig().getActSetItem(p_reqQryBat.ownAct,"");
            if (actItem != null) {
                String tmpBankBatchIdPath = getTempFileDirectory(p_reqQryBat.getBgnDateTime()) + File.separator + p_reqQryBat.reqBatchNO + ".txt";
                WriteBankLogLn2("快钱批次号映射文件路径:" + tmpBankBatchIdPath);
                if (!new File(tmpBankBatchIdPath).exists()) {
                    retAts.respCode = "-1";
                    retAts.respInfo = "本地未找到快钱批次号映射文件:" + tmpBankBatchIdPath;
                    retAts.writeAfterDetail();
                    return retAts;
                }
                String bankBatchId = FileHelper.readFileText(tmpBankBatchIdPath, getCharset());
                WriteBankLogLn2("快钱批次号映射文件内容:" + bankBatchId);

                JSONObject reqJson = new JSONObject();
                JSONObject reqHeaderJson = new JSONObject();
                reqHeaderJson.put("version","1.0.0");
                reqHeaderJson.put("messageType",NNBill01TransCode.batrec_9188Auth_query);
                reqHeaderJson.put("memberCode",actItem.inMerchantId);
                reqHeaderJson.put("batchId",bankBatchId);
                reqJson.put("head",reqHeaderJson);

                JSONObject reqBodyJson = new JSONObject();
                reqBodyJson.put("requestTime", Format.DateTime14Format.format(new Date()));
                reqBodyJson.put("startTime", "");
                reqBodyJson.put("endTime", "");
                reqBodyJson.put("externalRefNumber", "");
                reqBodyJson.put("txnStatus", "");
                reqBodyJson.put("pageNo", "1");
                reqBodyJson.put("pageSize", "1000");
                reqJson.put("body",reqBodyJson);
                reqJson.put("memberCode",actItem.inMerchantId);

                String[] tmpStrRet = sendDataToBank(actItem,reqJson, bankFront.getUrl("batUnified"));

                if (tmpStrRet[0].length() == 0) {
                    JSONObject respJsonObject = JSONObject.parseObject(tmpStrRet[1]);
                    String respHead = respJsonObject.getString(Cons.HEAD);
                    String respBody = respJsonObject.getString(Cons.RESPONSE_BODY);
                    if(respHead == null || respBody == null) {
                        retAts.respCode = "-1";
                        retAts.respInfo = "app-umgw返回报文head或responseBody节点缺失";
                        retAts.writeAfterDetail();
                        return retAts;
                    }
                    JSONObject respHeadJsonObject = JSONObject.parseObject(respHead);
                    JSONObject respBodyJsonObject = JSONObject.parseObject(respBody);
                    if(respHeadJsonObject.isEmpty()) {
                        retAts.respCode = "-1";
                        retAts.respInfo = "app-umgw返回报文head节点内容为空";
                        retAts.writeAfterDetail();
                        return retAts;
                    }
                    JSONObject decryptJO = new JSONObject();
                    if(!respBodyJsonObject.isEmpty()) {
                        CmsSignedAndEnveloped respEncryptObj = JSONObject.toJavaObject(respBodyJsonObject,CmsSignedAndEnveloped.class);
                        CryptoProcessorFactory.initCertDir(actItem.oppCertFilePath);
                        CryptoProcessorFactory.initCertDir(actItem.ownKeyStorePath);
                        decryptJO = MerchantPKIUtils.decrypt(actItem.oppCertFilePath, actItem.ownKeyStorePath, respEncryptObj);
                        WriteBankLogLn2("快钱响应明文body的json:\r\n" + JSON.toJSONString(decryptJO));
                    }
                    JSONObject respView = new JSONObject();
                    respView.put(Cons.HEAD, respHeadJsonObject);
                    respView.put(Cons.RESPONSE_BODY, decryptJO);
                    WriteBankLogLn2("解密后报文明文数据:\r\n" + JSON.toJSONString(respView));

                    String tmpRespCode = respHeadJsonObject.getString("responseCode");
                    if ("0000".equals(tmpRespCode)) {
                        retAts.respCode = "0";

                        String txnListContent = decryptJO.getString("txnList");
                        if(StringHelper.isNullOrEmpty(txnListContent)) {
                            retAts.respCode = "-1";
                            retAts.respInfo = "postRendering:respBody:txnList is null or a empty string";
                            retAts.writeAfterDetail();
                            return retAts;
                        }
                        String txnList = GZIPUtil.unGzip2(txnListContent, "UTF-8");
                        WriteBankLogLn2("postRendering:respBody:txnList=\r\n" + txnList);

                        JSONArray txnListArray = JSONArray.parseArray(txnList);
                        for(int i = 0; i < txnListArray.size(); i++){
                            JSONObject jsonDetail = txnListArray.getJSONObject(i);
                            RetAtsBatPayRecDetail tmpRetDetail = new RetAtsBatPayRecDetail();

                            tmpRetDetail.payAmount = StringHelper.amountDivide100(jsonDetail.getString("amount"));
                            tmpRetDetail.postScript = jsonDetail.getString("externalRefNumber");
                            tmpRetDetail.result = jsonDetail.getString("txnStatus");
                            tmpRetDetail.payInfoCode = jsonDetail.getString("bizResponseCode");
                            tmpRetDetail.memo = jsonDetail.getString("bizResponseMessage");
                            retAts.writeRetDetail(tmpRetDetail);
                        }
                    } else {
                        retAts.respCode = "-1";
                        retAts.respInfo = respHeadJsonObject.getString("responseTextMessage");
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = "银行返回内容为空!";
                }
            } else {
                retAts.respCode = "-1";
                retAts.respInfo = "未找到账号[" + p_reqQryBat.ownAct + "]商户配置信息,请检查config.xml中'actSet'相关配置!";
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            retAts.respCode = "-1";
            retAts.respInfo = ex.getMessage();
            WriteBankLogLn(ex);
        }

        retAts.writeAfterDetail();
        return retAts;
    }
}